Message Handlers topic

The way a state responds to a message is defined by the MessageHandler function for the state. A message handler is provided a MessageContext describing the message, and must return a MessageResult describing how the state responds to the message.

typedef MessageHandler = FutureOr<MessageResult> Function(MessageContext ctx);

Methods on the provided MessageContext can be used to create the desired message result. For example, goTo(), unhandled(), or stay()

Because a message handler returns a FutureOr, the handler implementation may be asynchronous if desired.

A message handler is provided with the onMessage callback when creating the state:

class GoToLogin { }
enum Messages { goToRegister }

State(
   States.unauthenticated,
   onMessage: (MessageContext ctx) {
      return switch(ctx.message) {
         // When this state receives a message of type GoToLogin, go to the login 
         // state
         GoToLogin() => ctx.goTo(States.login),
         // When this state receives a goToRegister message value, go to the 
         // registration state
         Messages.goToRegister => mhb.goTo(States.registration),
         // Otherwise, the message is unhandled. An ancestor state can handle it instead.
         _ => ctx.unhandled()
      }; 
   },
);

Reading and writing state data

A data state can access its associated state data. Additionally, any state can access the state data of an ancestor data state.

State data is stored in a DataValue<D> instance. A DataValue provides access to the current state data value with the value property. The DataValue for a data state can be requested using the MessageContext.data and TransitionContext.data methods.

A DataValue is also a Stream, and therefore can be used to observe changes to the state data over time. This is not typically used in a message handler, but DataValues are also accessible from a TreeStateMachine, and the change notifications can prove useful at the application level.

The DataValue.update method can be use to update the current value, which will cause the associated Stream to emit a new value.

State(
   States.credentialsRegistration, 
   onMessage: (ctx) {
      if (ctx.message case SubmitCredentials(email: var email, password: var password)) {
         // Update the RegisterData state data owned by an ancestor Register state. 
         ctx.data(States.register).update((RegisterData data) => data
            ..email = email
            ..password = password);
         return ctx.goTo(States.demographicsRegistration);
      } 
      return ctx.unhandled();
   },
);

Classes

DataState<D> State Trees Message Handlers Transition Handlers
A data state with associated state data of type D.
DataValue<T> Message Handlers
Provides access to a data value of type T associated with a data state.
MessageContext Message Handlers
Provides information to a state about the message that is being processed.
State State Trees Message Handlers Transition Handlers
A state in a state tree.

Typedefs

MessageHandler = FutureOr<MessageResult> Function(MessageContext ctx) Message Handlers
Type of functions that process messages sent to a state machine.